using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;


namespace Qreed.Xna
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class InputStateComponent : Microsoft.Xna.Framework.GameComponent
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="InputStateComponent"/> class.
        /// </summary>
        /// <param name="game">Game that the game component should be attached to.</param>
        public InputStateComponent(Game game)
            : base(game)
        {
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            base.Initialize();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            LastKeyboardState = CurrentKeyboardState;
            LastMouseState = CurrentMouseState;

            CurrentKeyboardState = Keyboard.GetState();
            CurrentMouseState = Mouse.GetState();

            for (int i = 0; i < (int)PlayerIndex.Four; i++)
            {
                LastGamePadState[i] = CurrentGamePadState[i];
                CurrentGamePadState[i] = GamePad.GetState((PlayerIndex)i);
            }

            base.Update(gameTime);
        }

        /// <summary>
        /// The current state of the keyboard
        /// </summary>
        public KeyboardState CurrentKeyboardState;

        /// <summary>
        /// The previous state of the keyboard
        /// </summary>
        public KeyboardState LastKeyboardState;

        /// <summary>
        /// The current state of the gamepad
        /// </summary>
        public GamePadState[] CurrentGamePadState = new GamePadState[4];

        /// <summary>
        /// The previous state of the gamepad
        /// </summary>
        public GamePadState[] LastGamePadState = new GamePadState[4];

        /// <summary>
        /// The current state of the mouse
        /// </summary>
        public MouseState CurrentMouseState;

        /// <summary>
        /// The previous state of the mouse
        /// </summary>
        public MouseState LastMouseState;

        /// <summary>
        /// Resets this instance.
        /// </summary>
        public void Reset()
        {
            LastGamePadState = CurrentGamePadState = new GamePadState[4];
            LastKeyboardState = CurrentKeyboardState = new KeyboardState();
            LastMouseState = CurrentMouseState = new MouseState();
        }

        /// <summary>
        /// Determines whether the key is currently pressed.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns>
        /// 	<c>true</c> if the key is down; otherwise, <c>false</c>.
        /// </returns>
        public bool IsKeyDown(Keys key)
        {
            return CurrentKeyboardState.IsKeyDown(key);
        }

        /// <summary>
        /// Determines whether the key isn't pressed.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns>
        /// 	<c>true</c> if the key isn't pressed; otherwise, <c>false</c>.
        /// </returns>
        public bool IsKeyUp(Keys key)
        {
            return CurrentKeyboardState.IsKeyUp(key);
        }

        /// <summary>
        /// Determines whether the key is pressed since the current frame
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns>
        /// 	<c>true</c> if the key is pressed; otherwise, <c>false</c>.
        /// </returns>
        public bool IsNewKeyDown(Keys key)
        {
            if (LastKeyboardState.IsKeyUp(key) &&
               CurrentKeyboardState.IsKeyDown(key))
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// Determines whether the key is up since the current frame
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns>
        /// 	<c>true</c> if the key is up; otherwise, <c>false</c>.
        /// </returns>
        public bool IsNewKeyUp(Keys key)
        {
            if (LastKeyboardState.IsKeyDown(key) &&
               CurrentKeyboardState.IsKeyUp(key))
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// Determines whether the button is pressed since the current frame
        /// </summary>
        /// <param name="button">The button.</param>
        /// <param name="playerIndex">Index of the player.</param>
        /// <returns>
        /// 	<c>true</c> if the button is pressed; otherwise, <c>false</c>.
        /// </returns>
        public bool IsNewButtonDown(Buttons button, PlayerIndex playerIndex)
        {
            if (LastGamePadState[(int)playerIndex].IsButtonUp(button) &&
                CurrentGamePadState[(int)playerIndex].IsButtonDown(button))
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// Determines whether the button is pressed since the current frame
        /// </summary>
        /// <param name="button">The button.</param>
        /// <returns>
        /// 	<c>true</c> if the button is pressed; otherwise, <c>false</c>.
        /// </returns>
        public bool IsNewButtonDown(Buttons button)
        {
            for (int i = 0; i < (int)PlayerIndex.Four; i++)
            {
                if (IsNewButtonDown(button, (PlayerIndex)i))
                    return true;
            }

            return false;
        }

        /// <summary>
        /// Determines whether the button is up since the current frame
        /// </summary>
        /// <param name="button">The button.</param>
        /// <param name="playerIndex">Index of the player.</param>
        /// <returns>
        /// 	<c>true</c> if the button is up; otherwise, <c>false</c>.
        /// </returns>
        public bool IsNewButtonUp(Buttons button, PlayerIndex playerIndex)
        {
            if (LastGamePadState[(int)playerIndex].IsButtonDown(button) &&
                CurrentGamePadState[(int)playerIndex].IsButtonUp(button))
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// Determines whether the button is up since the current frame
        /// </summary>
        /// <param name="button">The button.</param>
        /// <returns>
        /// 	<c>true</c> if the button is up; otherwise, <c>false</c>.
        /// </returns>
        public bool IsNewButtonUp(Buttons button)
        {
            for (int i = 0; i < (int)PlayerIndex.Four; i++)
            {
                if (IsNewButtonUp(button, (PlayerIndex)i))
                    return true;
            }

            return false;
        }
    }
}